﻿// 只测试IO，关于案例的测试在单元测试中保证。测试方案如下
// 1、用excel做样张+该文件说明（里面是要验证的单元格及其值还有名称）
// 2、ET读取测试与配置文件是否一致，存盘EXCEL&ET读取与配置文件比较
// 3、待测试的ET和Excel最好事先设置RC引用样式
#if ENABLE_EXCEL_COM
#if ENABLE_ET_COM

namespace suit_relsheet_io
{
    using System;
    using System.Xml;
    using System.Collections.Generic;

    public class CRelSheetIO : suit_base.SuiteBase
    {
        private string m_sEtAppPath;
        private string m_sExcelAppPath;
        private List<string> m_caseFileList;
        private CDumpData m_dumpDat;
        public CRelSheetIO()
        {
            m_caseFileList = new List<string>();
            m_dumpDat = new CDumpData();
        }

        public override string GetCommand()
        {
            return ET_Improve.Global.CMD_RELSHEET;
        }

        public override void Call()
        {
            try
            {
                LoadConfig();
                etOp.EtOp.ReRegisterET(m_sEtAppPath);
             //   excelOp.ExcelOP.RegisterExcel(m_sExcelAppPath);
                tool.LogTool.GetInstance().BeginUseLog(null, ET_Improve.Global.s_curCmdName);
                m_dumpDat.Begin();
                foreach (string _file in m_caseFileList)
                {
                    if(!TestCase(_file))
                    {
                        Console.WriteLine("Failed of Test:" + _file);
                    }
                    else
                    {
                        Console.WriteLine("Successed");
                    }
                }
                m_dumpDat.End();
            }
            catch(Exception ex)
            {
                tool.LogTool.GetInstance().AddLog(tool.LogTool.LOG_TYPE.ERROR, null,
                        ET_Improve.Global.s_curCmdName + " Failed!", ex);
            }
            finally
            {
                tool.LogTool.GetInstance().EndUseLog();
                tool.CTmpFileHlp.Clear();
            }
        }

        protected void LoadConfig()
        {
            const string LOG_ROOT = "relative-sheet-io";
            const string LOG_ET_PATH = "et-app-path";
            const string LOG_EXCEL_PATH = "excel-app-path";
            const string LOG_CASE = "case-file";
            try
            {
                foreach (XmlNode subNode in tool.ConfigReader.GetElementList(LOG_ROOT))
                {
                    switch(subNode.Name)
                    {
                        case LOG_CASE:
                            AddValidCaseFile(subNode.InnerText);
                            break;
                        case LOG_ET_PATH:
                            m_sEtAppPath = subNode.InnerText;
                            break;
                        case LOG_EXCEL_PATH:
                            m_sExcelAppPath = subNode.InnerText;
                            break;
                    }
                }
            }
            catch (System.Exception ex)
            {
                throw ex;
            }
        }

        protected void AddValidCaseFile(string sRelName)
        {
            string sAppPath = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;
            sAppPath = System.IO.Path.GetDirectoryName(sAppPath);

            string sFileName = sAppPath + "\\" + sRelName;
            if(!System.IO.File.Exists(sFileName))
            {
                string sCache = sFileName;
                sAppPath = System.IO.Path.GetDirectoryName(sAppPath);
                sAppPath = System.IO.Path.GetDirectoryName(sAppPath);
                sFileName = sAppPath + "\\" + sRelName;
                if (!System.IO.File.Exists(sFileName))
                {
                    tool.LogTool.GetInstance().AddLog(tool.LogTool.LOG_TYPE.ERROR,
                        null, sCache + " or " + sFileName + " not find!", null);
                    return;
                }
            }

            m_caseFileList.Add(sFileName);
        }

        protected bool TestCase(string sFileName)
        {
            // 1、read data frome config file
            CReadConfig readConfig = new CReadConfig(sFileName);
            CData configDat = readConfig.GetData();
            if(configDat == null)
            {
                return false;
            }
            // 2、 et open test, than save as
            string sEtSaved = null;
            if (!EtOpenSaveTest(configDat, sFileName, ref sEtSaved))
            {
                return false;
            }
            // 3、excel open test etSaved, than save as
            string sExcelSaved = null;
            if (!ExcelOpenSaveTest(configDat, sEtSaved, ref sExcelSaved))
            {
                return false;
            }
            // 4、et open test excelSaved.
            if(!EtOpenTest(configDat, sExcelSaved))
            {
                return false;
            }
            tool.CTmpFileHlp.Clear();
            return true;
        }

        protected bool EtOpenSaveTest(CData configDat, string sFileName, ref string sTmpFile)
        {
            try
            {
                CEtDerive pEt = new CEtDerive();
                CData rdDat = pEt.GetDataAndSaveAs(configDat, sFileName, ref sTmpFile);
                pEt = null;
                if (configDat != rdDat)
                {
                    m_dumpDat.AddData(rdDat, "EtOpenSaveTest");
                    return false;
                }
                return true;
            }
            catch (System.Exception ex)
            {
                tool.LogTool.GetInstance().AddLog(tool.LogTool.LOG_TYPE.ERROR, sFileName,
                        "Faild of EtOpenSaveTest", ex);
                return false;
            }
        }

        protected bool EtOpenTest(CData configDat, string sFileName)
        {
            try
            {
                CEtDerive pEt = new CEtDerive();
                CData rdDat = pEt.GetData(configDat, sFileName);
                pEt = null;
                if (configDat != rdDat)
                {
                    m_dumpDat.AddData(rdDat, "EtOpenTest");
                    return false;
                }
                return true;
            }
            catch (System.Exception ex)
            {
                tool.LogTool.GetInstance().AddLog(tool.LogTool.LOG_TYPE.ERROR, sFileName,
                    "Faild of EtOpenTest", ex);
                return false;
            }
        }

        protected bool ExcelOpenSaveTest(CData configDat, string sFileName, ref string sTmpFile)
        {
            try
            {
                CExcelDerive pXls = new CExcelDerive();
                CData rdDat = pXls.GetDataAndSaveAs(configDat, sFileName, ref sTmpFile);
                pXls = null;
                if (configDat != rdDat)
                {
                    m_dumpDat.AddData(rdDat, "ExcelOpenSaveTest");
                    return false;
                }
                return true;
            }
            catch (System.Exception ex)
            {
                tool.LogTool.GetInstance().AddLog(tool.LogTool.LOG_TYPE.ERROR, sFileName,
                    "Faild of ExcelOpenSaveTest", ex);
                return false;
            }
        }
    }

    class CDumpData
    {
        private XmlDocument m_doc;
        private XmlElement m_rootElem;
        private string m_sDumpName;
        public void Begin()
        {
            try
            {
                m_sDumpName = "rel_sheet_io_dump_" + DateTime.Now.ToString(
                    "MMddHHmm") + ".xml";
                m_doc = new XmlDocument();
                XmlDeclaration xmlDec = m_doc.CreateXmlDeclaration("1.0", "UTF-8", null);
                m_doc.InsertBefore(xmlDec, m_doc.DocumentElement);
                m_rootElem = m_doc.CreateElement("", "root", "");
                m_doc.AppendChild(m_rootElem);
            }
            catch (System.Exception ex)
            {
                tool.LogTool.GetInstance().AddLog(tool.LogTool.LOG_TYPE.ERROR, null,
                    "faild of dumpdata.begin", ex);
            }
        }

        public void End()
        {
            try
            {
                if (m_doc == null)
                {
                    return;
                }
                m_doc.Save(m_sDumpName);
                m_doc = null;
            }
            catch (System.Exception ex)
            {
                tool.LogTool.GetInstance().AddLog(tool.LogTool.LOG_TYPE.ERROR, null,
                    "faild of dumpdata.end", ex);
            }
        }

        public void AddData(CData dat, string sRemark)
        {
            if(dat == null)
            {
                return;
            }
            XmlElement node = m_doc.CreateElement("", sRemark, "");
            AddName(dat, node);
            AddCell(dat, node);
            m_rootElem.AppendChild(node);
        }

        protected void AddName(CData dat, XmlElement root)
        {
            const string XML_NAME_DEF = "namedefined";
            const string XML_NAME = "name";
            const string XML_REFER = "refer";
            XmlElement nameRoot = m_doc.CreateElement("", XML_NAME_DEF, "");
            int nCount = dat.GetNameCount();
            for(int i = 0; i < nCount; ++i)
            {
                CName nm = dat.GetNameItem(i);
                XmlElement node = m_doc.CreateElement("", XML_NAME, "");
                node.SetAttribute(XML_NAME, nm.Name);
                node.SetAttribute(XML_REFER, nm.ReferRC);
                nameRoot.AppendChild(node);
            }
            root.AppendChild(nameRoot);
        }

        protected void AddCell(CData dat, XmlElement root)
        {
            const string XML_SHEET = "worksheet";
            const string XML_IDX = "idx";
            for (int i = 0; i < dat.GetSheetCount(); ++i)
            {
                XmlElement node = m_doc.CreateElement("", XML_SHEET, "");
                node.SetAttribute(XML_IDX, i.ToString());
                AddSheetCell(dat, node, i);
                root.AppendChild(node);
            }
        }

        protected void AddSheetCell(CData dat, XmlElement root, int iSheet)
        {
            const string XML_CELL = "cell";
            const string XML_POS = "pos";
            const string XML_VALUE = "value";

            int nCount = dat.GetCellCount(iSheet);
            for (int i = 0; i < nCount; ++i)
            {
                CCell cx = dat.GetCellItem(iSheet, i);
                XmlElement node = m_doc.CreateElement("", XML_CELL, "");
                node.SetAttribute(XML_POS, cx.Pos);
                node.SetAttribute(XML_VALUE, cx.Value);
                root.AppendChild(node);
            }
        }
    }

    // 必须设置RC引用
    class CEtDerive : etOp.EtOp
    {
        public CData GetDataAndSaveAs(CData oriDat, string sFileName, ref string sSaveFile)
        {
            return _GetData(oriDat, sFileName, true, ref sSaveFile);
        }

        public CData GetData(CData oriDat, string sFileName)
        {
            string sNone = null;
            return _GetData(oriDat, sFileName, false, ref sNone);
        }

        protected CData _GetData(CData oriDat, string sFileName, bool bSaveAs,
            ref string sSaveFile)
        {
            Open(sFileName, null);
            CData retDat = new CData();
            GetNameDat(retDat);
            for (int iSheet = 0; iSheet < oriDat.GetSheetCount(); ++iSheet)
            {
                GetSheetCellValue(iSheet, oriDat, retDat);
            }
            // Save As
            if (!bSaveAs)
            {
                return retDat;
            }
            sSaveFile = tool.CTmpFileHlp.GetSystemTmpName(m_sCurFileName);
            SaveAsFile(sSaveFile);
            tool.CTmpFileHlp.AddTmpFile(sSaveFile);
            Close();
            return retDat;
        }

        protected void GetNameDat(CData rdDat)
        {
            m_app.ReferenceStyle = ET.ETReferenceStyle.etR1C1;
            int nCount = m_workbook.Names.Count;
            ET.Names names = m_workbook.Names;
            foreach (ET.Name name in m_workbook.Names)
            {
                CName nm = new CName();
                nm.Name = name.Name;
                nm.ReferRC = name.RefersTo;
                rdDat.AddName(nm);
                NAR(name);
            }
            NAR(names);
        }

        protected void GetSheetCellValue(int iSheet, CData oriDat, CData rdDat)
        {
            // 这个待会跟一下，这个Count到底是怎么搞的
            if(iSheet >= m_app.Worksheets.Count)
            {
                return;
            }
            ET.Worksheet ws = (ET.Worksheet)m_app.Worksheets[iSheet + 1];
            int nCount = oriDat.GetCellCount(iSheet);
            for (int i = 0; i < nCount; ++i)
            {
                CCell oriCx = oriDat.GetCellItem(iSheet, i);
                CCell rdCx = new CCell();
                rdCx.Pos = oriCx.Pos;
                ET.Range etRg = ws.get_Range(rdCx.Pos, Type.Missing);
                rdCx.Value = string.Format("{0}", etRg.Value2);
                rdDat.AddCell(iSheet, rdCx);
                NAR(etRg);
            }
            NAR(ws);
        }
    }

    class CExcelDerive : excelOp.ExcelOP
    {
        public CData GetDataAndSaveAs(CData oriDat, string sFileName, ref string sSaveFile)
        {
            return _GetData(oriDat, sFileName, true, ref sSaveFile);
        }

        public CData GetData(CData oriDat, string sFileName)
        {
            string sNone = null;
            return _GetData(oriDat, sFileName, false, ref sNone);
        }

        protected CData _GetData(CData oriDat, string sFileName, bool bSaveAs,
            ref string sSaveFile)
        {
            Open(sFileName, null);
            CData retDat = new CData();
            GetNameDat(retDat);
            for (int iSheet = 0; iSheet < oriDat.GetSheetCount(); ++iSheet)
            {
                GetSheetCellValue(iSheet, oriDat, retDat);
            }
            // Save As
            if (!bSaveAs)
            {
                return retDat;
            }
            sSaveFile = tool.CTmpFileHlp.GetSystemTmpName(m_sCurFilename);
            SaveAs(sSaveFile);
            tool.CTmpFileHlp.AddTmpFile(sSaveFile);
            Close();
            return retDat;
        }

        protected void GetNameDat(CData rdDat)
        {
            m_app.ReferenceStyle = Microsoft.Office.Interop.Excel.XlReferenceStyle.xlR1C1;
            int nCount = m_workbook.Names.Count;
            Microsoft.Office.Interop.Excel.Names names = m_workbook.Names;
            foreach (Microsoft.Office.Interop.Excel.Name name in m_workbook.Names)
            {
                CName nm = new CName();
                nm.Name = name.Name;
                nm.ReferRC = string.Format("{0}", name.RefersToR1C1);
                rdDat.AddName(nm);
                NAR(name);
            }
            NAR(names);
        }

        protected void GetSheetCellValue(int iSheet, CData oriDat, CData rdDat)
        {
            // 这个待会跟一下，这个Count到底是怎么搞的
            if (iSheet >= m_app.Worksheets.Count)
            {
                return;
            }
            Microsoft.Office.Interop.Excel.Worksheet ws = (Microsoft.Office.Interop.Excel.Worksheet)m_app.Worksheets[iSheet + 1];
            int nCount = oriDat.GetCellCount(iSheet);
            for (int i = 0; i < nCount; ++i)
            {
                CCell oriCx = oriDat.GetCellItem(iSheet, i);
                CCell rdCx = new CCell();
                rdCx.Pos = oriCx.Pos;
                Microsoft.Office.Interop.Excel.Range etRg = ws.get_Range(rdCx.Pos, Type.Missing);
                rdCx.Value = string.Format("{0}", etRg.Value2);
                rdDat.AddCell(iSheet, rdCx);
                NAR(etRg);
            }
            NAR(ws);
        }
    }

    public class CData
    {
        private List<CName> m_nameList;
        private List<List<CCell>> m_cellList;
        public CData()
        {
            m_nameList = new List<CName>();
            m_cellList = new List<List<CCell>>();
        }

        public void AddName(CName nm)
        {
            m_nameList.Add(nm);
        }

        public void AddCell(int iSheet, CCell cx)
        {
            List<CCell> lst;
            if(iSheet < m_cellList.Count)
            {
                lst = m_cellList[iSheet];
            }
            else
            {
                lst = new List<CCell>();
                m_cellList.Add(lst);
            }
            lst.Add(cx);
        }

        public int GetNameCount()
        {
            return m_nameList.Count;
        }

        public CName GetNameItem(int idx)
        {
            if(idx < m_nameList.Count)
            {
                return m_nameList[idx];
            }
            return null;
        }

        public int GetSheetCount()
        {
            return m_cellList.Count;
        }

        public int GetCellCount(int iSheet)
        {
            if(iSheet < m_cellList.Count)
            {
                return m_cellList[iSheet].Count;
            }
            return 0;
        }

        public CCell GetCellItem(int iSheet, int idx)
        {
            if(iSheet >= m_cellList.Count)
            {
                return null;
            }

            List<CCell> cxLst = m_cellList[iSheet];
            if(idx >= cxLst.Count)
            {
                return null;
            }
            return cxLst[idx];
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        public bool Equals(CData other)
        {
            if (ReferenceEquals(null, other))
            {
                return false;
            }
            if (ReferenceEquals(this, other))
            {
                return true;
            }

            if(m_nameList.Count != other.GetNameCount())
            {
                return false;
            }
            int nCount = m_nameList.Count;
            for(int i = 0; i < nCount; ++i)
            {
                if(m_nameList[i] != other.GetNameItem(i))
                {
                    return false;
                }
            }

            if(m_cellList.Count != other.GetSheetCount())
            {
                return false;
            }
            int nSheets = m_cellList.Count;
            for(int idx = 0; idx < nSheets; ++idx)
            {
                List<CCell> cxLst1 = m_cellList[idx];
                if (cxLst1.Count != other.GetCellCount(idx))
                {
                    return false;
                }
                for (int k = 0; k < cxLst1.Count; ++k)
                {
                    if(cxLst1[k] != other.GetCellItem(idx, k))
                    {
                        return false;
                    }
                }
            }

            return true;
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj))
            {
                return false;
            }
            if (ReferenceEquals(this, obj))
            {
                return true;
            }
            if (obj.GetType() != typeof(CData))
            {
                return false;
            }
            return Equals((CData)obj);
        }

        public static bool operator ==(CData left, CData right)
        {
            return Equals(left, right);
        }

        public static bool operator !=(CData left, CData right)
        {
            return !Equals(left, right);
        }
    }

    public class CName
    {
        public string Name { set; get; }
        public string ReferRC { set; get; }
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        public bool Equals(CName other)
        {
            if (ReferenceEquals(null, other))
            {
                return false;
            }
            if (ReferenceEquals(this, other))
            {
                return true;
            }
            return Name == other.Name && ReferRC == other.ReferRC;
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj))
            {
                return false;
            }
            if (ReferenceEquals(this, obj))
            {
                return true;
            }
            if (obj.GetType() != typeof(CName))
            {
                return false;
            }
            return Equals((CName)obj);
        }

        public static bool operator ==(CName left, CName right)
        {
            return Equals(left, right);
        }

        public static bool operator !=(CName left, CName right)
        {
            return !Equals(left, right);
        }
    }

    public class CCell
    {
        public string Pos { set; get; }
        public string Value { set; get; }
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        public bool Equals(CCell other)
        {
            if (ReferenceEquals(null, other))
            {
                return false;
            }
            if (ReferenceEquals(this, other))
            {
                return true;
            }
            return Pos == other.Pos && Value == other.Value;
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj))
            {
                return false;
            }
            if (ReferenceEquals(this, obj))
            {
                return true;
            }
            if (obj.GetType() != typeof(CCell))
            {
                return false;
            }
            return Equals((CCell)obj);
        }

        public static bool operator ==(CCell left, CCell right)
        {
            return Equals(left, right);
        }

        public static bool operator !=(CCell left, CCell right)
        {
            return !Equals(left, right);
        }
    }

    // 读取文件配置数据
    class CReadConfig
    {
        private string m_fileName;
        private CData m_data;
        public CReadConfig(string sCaseFile)
        {
            m_data = new CData();
            m_fileName = System.IO.Path.ChangeExtension(sCaseFile, "xml");
        }

        public CData GetData()
        {
            if(ReadConfigValue())
            {
                return m_data;
            }
            return null;
        }

        protected bool ReadConfigValue()
        {
            const string XML_NAMEROOT = "namedefined";
            const string XML_WORKSHEET = "worksheet";
            const string XML_SHEET_ID = "idx";
            try
            {
                XmlDocument doc = new XmlDocument();
                doc.Load(m_fileName);
                XmlElement docEle = doc.DocumentElement;
                foreach (XmlNode node in docEle.ChildNodes)
                {
                    if(node.Name == XML_NAMEROOT)
                    {
                        ReadNameData(node.ChildNodes);
                    }
                    else if (node.Name == XML_WORKSHEET)
                    {
                        XmlElement xe = (XmlElement)node;
                        string sId = xe.GetAttribute(XML_SHEET_ID);
                        ReadSheetCellData(int.Parse(sId), node.ChildNodes);
                    }
                }
                return true;
            }
            catch(tool.ETImpException ex)
            {
                ex.AddLog();
                return false;
            }
            catch (System.Exception ex)
            {
                tool.LogTool.GetInstance().AddLog(tool.LogTool.LOG_TYPE.ERROR,
                    null, "read config file", ex);
                return false;
            }
        }

        protected void ReadNameData(XmlNodeList xnl)
        {
            const string XML_NAME = "name";
            const string XML_REFER = "refer";
            try
            {
                foreach (XmlNode xn in xnl)
                {
                    XmlElement xe = (XmlElement)xn;
                    if(xe.Name == XML_NAME)
                    {
                        CName nm = new CName();
                        nm.Name = xe.GetAttribute(XML_NAME);
                        nm.ReferRC = xe.GetAttribute(XML_REFER);
                        m_data.AddName(nm);
                    }
                }
            }
            catch (System.Exception ex)
            {
                throw new tool.ETImpException(tool.LogTool.LOG_TYPE.ERROR, null,
                    "Failed of read name data frome xml config file", ex);
            }
        }

        protected void ReadSheetCellData(int iSheet, XmlNodeList xnl)
        {
            const string XML_CELL = "cell";
            const string XML_POS = "pos";
            const string XML_VALUE = "value";
            try
            {
                foreach (XmlNode xn in xnl)
                {
                    if(xn.Name == XML_CELL)
                    {
                        XmlElement xe = (XmlElement)xn;
                        CCell cx = new CCell();
                        cx.Pos = xe.GetAttribute(XML_POS);
                        cx.Value = xe.GetAttribute(XML_VALUE);
                        m_data.AddCell(iSheet, cx);
                    }
                }
            }
            catch (System.Exception ex)
            {
                throw new tool.ETImpException(tool.LogTool.LOG_TYPE.ERROR, null,
                        "Failed of read cell data frome xml config file", ex);
            }
        }
    }
}

#endif  // #if ENABLE_ET_COM
#endif  // #if ENABLE_EXCEL_COM